/** @file    CoderXML_Entertainment.cpp
 *  @author  Alessandro Polo
 *  @version $Id: CoderXML_Entertainment.cpp 2080 2010-03-10 05:38:54Z alex $
 *  @brief
 * File containing methods for Serialization.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include <framework/database/CoderXML_Entertainment.h>
 #include <framework/database/CoderXML_Core.h>
 #include <framework/database/EncoderXML.h>


using namespace std;
using namespace wosh::entertainment;
namespace wosh {
 namespace database {

void EncoderXML_register_Entertainment()
 {
	EncoderXML::registerDataType( _MediaList_TYPE,		new EncoderXML_template__MediaList() );
	EncoderXML::registerDataType( _MediaTrack_TYPE,		new EncoderXML_template__MediaTrack() );
	EncoderXML::registerDataType( _MediaZone_TYPE,		new EncoderXML_template__MediaZone() );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT EncoderXML_template__MediaTrack::serializeTo( const ISerializable* object_s, QDomDocument& doc, QDomElement& contNode, bool compact )
 {
	if ( object_s == NULL ) return WRET_ERR_PARAM;
	const wosh::entertainment::MediaTrack* object = dynamic_cast<const wosh::entertainment::MediaTrack*>(object_s);
	if ( object == NULL ) return WRET_ERR_PARAM;
	WRESULT ret = WRET_OK;

	if ( compact ) {
		contNode.setAttribute("resource", QString(object->getTrack().getPathFull().c_str()) );
	 }
	else {
		QDomElement resourceNode = doc.createElement("resource");
		resourceNode.appendChild( doc.createTextNode( object->getTrack().getPathFull().c_str() ) );
		contNode.appendChild(resourceNode);
	 }

	if ( !object->getProperties().isEmpty() ) {
		QDomElement propsNode = doc.createElement("properties");
		contNode.appendChild(propsNode);
		ret += EncoderXML_template__PropertiesProvider().serializeTo( &object->getProperties(), doc, propsNode, compact );
	 }

	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT EncoderXML_template__MediaTrack::deserializeFrom( ISerializable* object_s, const QDomElement& contNode )
 {
 	if ( object_s == NULL ) return WRET_ERR_PARAM;
	wosh::entertainment::MediaTrack* object = dynamic_cast<wosh::entertainment::MediaTrack*>(object_s);
	if ( object == NULL ) return WRET_ERR_PARAM;
	WRESULT ret = WRET_OK;

	QDomElement resourceNode = contNode.namedItem("resource").toElement();
	if ( contNode.hasAttribute("resource") )
		object->getTrack().set( contNode.attribute("resource").toLatin1().data() );
	else if ( !resourceNode.isNull() )
		object->getTrack().set( resourceNode.text().toLatin1().data() );
	else
		object->getTrack().setPath( contNode.text().toLatin1().data() );

	QDomElement propsNode = contNode.namedItem("properties").toElement();
	if ( !propsNode.isNull() )
		ret += EncoderXML_template__PropertiesProvider().deserializeFrom( object, propsNode );
	else
		ret += EncoderXML_template__PropertiesProvider().deserializeFrom( object, contNode );

	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT EncoderXML_template__MediaList::serializeTo( const ISerializable* object_s, QDomDocument& doc, QDomElement& contNode, bool compact )
 {
	if ( object_s == NULL ) return WRET_ERR_PARAM;
	const wosh::entertainment::MediaList* object = dynamic_cast<const wosh::entertainment::MediaList*>(object_s);
	if ( object == NULL ) return WRET_ERR_PARAM;
	WRESULT ret = WRET_OK;

	if ( compact ) {
		ret += EncoderXML_template__Object().serializeTo( object, doc, contNode, true );
	 }
	else {
		QDomElement objectNode = doc.createElement("object");
		contNode.appendChild(objectNode);
		ret += EncoderXML_template__Object().serializeTo( object, doc, objectNode, false );
	 }

	QDomElement stateNode = doc.createElement("state");
	contNode.appendChild(stateNode);
	if ( compact ) {
		stateNode.setAttribute("index", QString::number(object->getCurrentIndex()) );
		stateNode.setAttribute("position", QString::number(object->getCurrentPosition()) );
	 }
	else {
		QDomElement indexNode = doc.createElement("index");
		indexNode.appendChild( doc.createTextNode( QString::number(object->getCurrentIndex()) ) );
		stateNode.appendChild(indexNode);

		QDomElement posNode = doc.createElement("position");
		posNode.appendChild( doc.createTextNode( QString::number(object->getCurrentPosition()) ) );
		stateNode.appendChild(posNode);
	 }

	QDomElement tracksNode = doc.createElement("tracks");
	contNode.appendChild(tracksNode);

	WRESULT ret_t = WRET_OK;
	EncoderXML_template__MediaTrack encoder;

	List22<MediaTrack*>::ConstIterator it;
	for ( it=object->getTracks().begin(); it!=object->getTracks().end(); ++it ) {
		if ( *it == NULL ) continue;
		QDomElement trackNode = doc.createElement("track");
		ret_t = encoder.serializeTo( *it, doc, trackNode, true );
		if ( WSUCCEEDED(ret_t) )
			tracksNode.appendChild(trackNode);
		ret += ret_t;
	 }

	if ( !object->getProperties().isEmpty() ) {
		QDomElement propsNode = doc.createElement("properties");
		contNode.appendChild(propsNode);
		ret += EncoderXML_template__PropertiesProvider().serializeTo( &object->getProperties(), doc, propsNode, compact );
	 }

	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT EncoderXML_template__MediaList::deserializeFrom( ISerializable* object_s, const QDomElement& contNode )
 {
 	if ( object_s == NULL ) return WRET_ERR_PARAM;
	wosh::entertainment::MediaList* object = dynamic_cast<wosh::entertainment::MediaList*>(object_s);
	if ( object == NULL ) return WRET_ERR_PARAM;
	WRESULT ret = WRET_OK;

	QDomElement objectNode = contNode.namedItem("object").toElement();
	if ( !objectNode.isNull() )
		ret += EncoderXML_template__Object().deserializeFrom( object, objectNode );
	else
		ret += EncoderXML_template__Object().deserializeFrom( object, contNode );

	QDomElement tracksNode = contNode.namedItem("tracks").toElement();
	if ( !tracksNode.isNull() ) {
		string tagname;
		MediaTrack track_element;
		EncoderXML_template__MediaTrack encoder;
		QDomNodeList nodesList = tracksNode.childNodes();
		for( unsigned int j=0; j<nodesList.length(); j++ ) {
			QDomElement childNode = nodesList.item(j).toElement();
			track_element.clear();
			encoder.deserializeFrom( &track_element, childNode );
			object->getTracks().push_back(track_element.clone());
		 }
	 }

	QDomElement stateNode = contNode.namedItem("state").toElement();
	if ( !stateNode.isNull() ) {
		QDomElement indexNode = stateNode.namedItem("index").toElement();
		if ( indexNode.isNull() )
			object->setCurrentIndex( stateNode.attribute("index").toLong() );
		else
			object->setCurrentIndex( indexNode.text().toLong() );

		QDomElement posNode = stateNode.namedItem("position").toElement();
		if ( posNode.isNull() )
			object->setCurrentPosition( stateNode.attribute("position").toLong() );
		else
			object->setCurrentPosition( posNode.text().toLong() );
	 }

	QDomElement propsNode = contNode.namedItem("properties").toElement();
	if ( !propsNode.isNull() )
		ret += EncoderXML_template__PropertiesProvider().deserializeFrom( &object->getProperties(), propsNode );
	else
		ret += EncoderXML_template__PropertiesProvider().deserializeFrom( &object->getProperties(), contNode );

	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT EncoderXML_template__MediaZone::serializeTo( const ISerializable* object_s, QDomDocument& doc, QDomElement& contNode, bool compact )
 {
	if ( object_s == NULL ) return WRET_ERR_PARAM;
	const wosh::entertainment::MediaZone* object = dynamic_cast<const wosh::entertainment::MediaZone*>(object_s);
	if ( object == NULL ) return WRET_ERR_PARAM;
	WRESULT ret = WRET_OK;

	if ( compact ) {
		ret += EncoderXML_template__Object().serializeTo( object, doc, contNode, true );
	 }
	else {
		QDomElement objectNode = doc.createElement("object");
		contNode.appendChild(objectNode);
		ret += EncoderXML_template__Object().serializeTo( object, doc, objectNode, false );
	 }

	//contNode.setAttribute("id", QString::number(object->getID()) );
	contNode.setAttribute("timestamp", QString::number(object->getSeen()) );

	contNode.setAttribute("parent", QString(object->getParent().c_str()) );

	//MediaZone::ZONE_TYPE zoneType;
	//vector<string> children;

	QDomElement mapsNode = doc.createElement("mappings");
	contNode.appendChild(mapsNode);
	Map22<URI, int>::ConstIterator it_c;
	const Map22<URI, int>::ConstIterator it_c_end = object->getKeyMappings().end();
	for ( it_c=object->getKeyMappings().begin(); it_c!=it_c_end; ++it_c ) {
		QDomElement mapNode = doc.createElement("bobj");
		mapNode.appendChild( doc.createTextNode( QString(it_c->first.toString().c_str()) ) );
		contNode.setAttribute("action", QString::number(it_c->second) );
		mapsNode.appendChild(mapNode);
	 }

	QDomElement propsNode = doc.createElement("properties");
	contNode.appendChild(propsNode);
	ret += EncoderXML_template__PropertiesProvider().serializeTo( &object->getProperties(), doc, propsNode, compact );

	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT EncoderXML_template__MediaZone::deserializeFrom( ISerializable* object_s, const QDomElement& contNode )
 {
 	if ( object_s == NULL ) return WRET_ERR_PARAM;
	wosh::entertainment::MediaZone* object = dynamic_cast<wosh::entertainment::MediaZone*>(object_s);
	if ( object == NULL ) return WRET_ERR_PARAM;
	WRESULT ret = WRET_OK;

	QDomElement objectNode = contNode.namedItem("object").toElement();
	if ( !objectNode.isNull() )
		ret += EncoderXML_template__Object().deserializeFrom( object, objectNode );
	else
		ret += EncoderXML_template__Object().deserializeFrom( object, contNode );

	QDomElement contNode_type = contNode.namedItem("zone-type").toElement();
	if ( contNode_type.isNull() )
		object->setZoneType( MediaZone::getZoneTypeFromString(contNode.attribute("zone-type").toLatin1().data()) );
	else
		object->setZoneType( MediaZone::getZoneTypeFromString(contNode_type.text().toLatin1().data()) );

	QDomElement contNode_loc = contNode.namedItem("location").toElement();
	if ( contNode_loc.isNull() )
		object->setLocationURI( contNode.attribute("location").toLatin1().data() );
	else
		object->setLocationURI( contNode_loc.text().toLatin1().data() );

	QDomElement relationsNode = contNode.namedItem("relations").toElement();
	if ( !relationsNode.isNull() ) {
		if ( relationsNode.hasAttribute("parent") )
			object->setParent( string( relationsNode.attribute("parent").toLatin1().data() ) );
		QDomNodeList childrenList = relationsNode.childNodes();
		for( unsigned int j=0; j<childrenList.length(); ++j ) {
			QDomElement childNode = childrenList.item(j).toElement();
			if ( childNode.tagName() == "parent" )
				object->setParent( string( childNode.text().toLatin1().data() ) );
			else if ( childNode.tagName() == "child" ) {
				string name = childNode.text().toLatin1().data();
				if ( object->getChildren().find(name) == object->getChildren().end() )
					object->getChildren()[name] = string(childNode.attribute("action").toLatin1().data());
			 }
		 }
	 }

	QDomElement devices_node = contNode.namedItem("devices").toElement();
	QDomNodeList devicesList = devices_node.childNodes();
	for( unsigned int j=0; j<devicesList.length(); ++j ) {
		QDomElement childNode = devicesList.item(j).toElement();
		string uri = childNode.attribute("uri").toLatin1().data();
		object->setPlayerURI( uri );
		break;
	 }

	QDomElement mappings_node = contNode.namedItem("mappings").toElement();
	QDomNodeList mappingsList = mappings_node.childNodes();
	for( unsigned int j=0; j<mappingsList.length(); ++j ) {
		QDomElement childNode = mappingsList.item(j).toElement();
		int cmd = MediaZone::getCommandFromString( string(childNode.attribute("action").toLatin1().data()) );
		object->getKeyMappings().set( string(childNode.text().toLatin1().data()), cmd );
	 }

	QDomElement propsNode = contNode.namedItem("properties").toElement();
	if ( !propsNode.isNull() )
		ret += EncoderXML_template__PropertiesProvider().deserializeFrom( &object->getProperties(), propsNode );
	else
		ret += EncoderXML_template__PropertiesProvider().deserializeFrom( &object->getProperties(), contNode );

	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 }; // namespace database
}; // namespace wosh
